﻿#include <condition_variable>
#include <iostream>
#include <mutex>

#include "dap/io.h"
#include "dap/network.h"
#include "dap/protocol.h"
#include "dap/session.h"

int main(int, char*[]) {
  constexpr int kPort = 19528;

  // 当有新连接时
  auto onClientConnected = [&](const std::shared_ptr<dap::ReaderWriter>&
                                   socket) {
    // 创建会话
    std::shared_ptr<dap::Session> session = dap::Session::create();
    // Set the session to close on invalid data. This ensures that data received over the network
    // receives a baseline level of validation before being processed.
    session->setOnInvalidData(dap::kClose);
    session->bind(socket);

    // 收到client发来的初始化信息
    session->registerHandler([&](const dap::InitializeRequest&) {
      printf("Server received initialize request from client\n");
      // 返回服务端当前的能力
      dap::InitializeResponse response = {};
      // the adapter implements the configurationDone request.
      response.supportsConfigurationDoneRequest = true;
      // make VS Code use 'evaluate' when hovering over source
      response.supportsEvaluateForHovers = true;
      // make VS Code show a 'step back' button
      response.supportsStepBack = true;
      // make VS Code support data breakpoints
      response.supportsDataBreakpoints = true;
      // make VS Code support completion in REPL
      response.supportsCompletionsRequest = true;
      response.completionTriggerCharacters = {".", "["};
      // make VS Code send cancel request
      response.supportsCancelRequest = true;
      // make VS Code send the breakpointLocations request
      response.supportsBreakpointLocationsRequest = true;
      // make VS Code provide "Step in Target" functionality
      response.supportsStepInTargetsRequest = true;
      // the adapter defines two exceptions filters, one with support for conditions.
      response.supportsExceptionFilterOptions = true;
      dap::ExceptionBreakpointsFilter exceptionFilter0{}, exceptionFilter1{};
      exceptionFilter0.filter = "namedException";
      exceptionFilter0.label = "Named Exception";
      exceptionFilter0.description =
          "Break on named exceptions. Enter the exception's name as "
          "the Condition.";
      exceptionFilter0.def = false;
      exceptionFilter0.supportsCondition = true;
      exceptionFilter0.conditionDescription = "Enter the exception's name";
      exceptionFilter1.filter = "otherExceptions";
      exceptionFilter1.label = "Other Exceptions";
      exceptionFilter1.description = "This is a other exception";
      exceptionFilter1.def = true;
      exceptionFilter1.supportsCondition = false;
      response.exceptionBreakpointFilters = {exceptionFilter0,
                                             exceptionFilter1};

      // make VS Code send exceptionInfo request
      response.supportsExceptionInfoRequest = true;
      // make VS Code send setVariable request
      response.supportsSetVariable = true;
      // make VS Code send setExpression request
      response.supportsSetExpression = true;
      // make VS Code send disassemble request
      response.supportsDisassembleRequest = true;
      response.supportsSteppingGranularity = true;
      response.supportsInstructionBreakpoints = true;
      // make VS Code able to read and write variable memory
      response.supportsReadMemoryRequest = true;
      response.supportsWriteMemoryRequest = true;

      response.supportSuspendDebuggee = true;
      response.supportTerminateDebuggee = true;
      response.supportsFunctionBreakpoints = true;
      response.supportsDelayedStackTraceLoading = true;

      return response;
    });

    // 返回服务端已准备好接收配置请求
    session->registerSentHandler(
        [&](const dap::ResponseOrError<dap::InitializeResponse>&) {
          printf("Server response initialized\n");
          session->send(dap::InitializedEvent());
        });

    // 处理 Launch 请求
    session->registerHandler([&](const dap::LaunchRequest& request) {
      printf("Server received launch request\n");
      return dap::LaunchResponse();
    });

        // 处理 Threads 请求
    session->registerHandler([](const dap::ThreadsRequest& request) {
      printf("Server received threads request\n");
      dap::ThreadsResponse response;
      // 模拟只有一个线程
      dap::Thread thread;
      thread.id = 1;
      thread.name = "Thread 1";
      response.threads.push_back(thread);
      return response;
    });

    // 处理 StackTrace 请求
    session->registerHandler([](const dap::StackTraceRequest& request) {
      printf("Server received stack trace request\n");
      dap::StackTraceResponse response;
      // 模拟调用堆栈
      dap::StackFrame frame;
      frame.id = 0;
      frame.name = "main";
      // 设置源文件信息
      dap::Source source;
      source.name = "source.cpp";
      source.sourceReference = 1;
      frame.source = source;
      response.stackFrames.push_back(frame);
      return response;
    });

    // 处理 Variables 请求
    session->registerHandler([](const dap::VariablesRequest& request) {
      printf("Server received variables request\n");
      dap::VariablesResponse response;
      // 模拟变量
      dap::Variable variable;
      variable.name = "var1";
      variable.value = "value1";
      response.variables.push_back(variable);
      return response;
    });

    // 处理 Continue 请求
    session->registerHandler([](const dap::ContinueRequest& request) {
      printf("Server received continue request\n");
      return dap::ContinueResponse();
    });

    // 处理 Next 请求
    session->registerHandler(
        [](const dap::NextRequest& request) {
          printf("Server received next request\n");
          return dap::NextResponse();
        });

    // 处理 StepIn 请求
    session->registerHandler([](const dap::StepInRequest& request) {
      printf("Server received step request\n");
      return dap::StepInResponse();
    });

    // 处理 StepOut 请求
    session->registerHandler([](const dap::StepOutRequest& request) {
      printf("Server received step out request\n");
      return dap::StepOutResponse();
    });

    // 处理 SetBreakpoints 请求
    session->registerHandler([](const dap::SetBreakpointsRequest& request) {
      printf("Server received set breakpoints request\n");
      dap::SetBreakpointsResponse response;
      if (request.source.sourceReference.value() == 1) {
        // 模拟设置断点
        for (const auto& breakpoint : request.breakpoints.value()) {
          if (breakpoint.line > 0) {
            dap::Breakpoint bp;
            bp.verified = true;
            bp.line = breakpoint.line;
            response.breakpoints.push_back(bp);
          }
        }
      }
      return response;
    });

    // 处理 Source 请求
    session->registerHandler([](const dap::SourceRequest& request) {
      printf("Server received source request\n");
      dap::SourceResponse response;
      if (request.sourceReference == 1) {
        // 模拟源代码
        response.content = "int main() {\n  return 0;\n}";
      }
      return response;
    });

    // 处理 ConfigurationDone 请求
    session->registerHandler([](const dap::ConfigurationDoneRequest& request) {
      printf("Server received configuration request\n");
      return dap::ConfigurationDoneResponse();
    });










    // Signal used to terminate the server session when a DisconnectRequest
    // is made by the client.
    bool terminate = false;
    std::condition_variable cv;
    std::mutex mutex;// guards 'terminate'

    // The Disconnect request is made by the client before it disconnects
    // from the server.
    // https://microsoft.github.io/debug-adapter-protocol/specification#Requests_Disconnect
    session->registerHandler([&](const dap::DisconnectRequest&) {
      printf("Server received disconnect request\n");
      // Client wants to disconnect. Set terminate to true, and signal the
      // condition variable to unblock the server thread.
      std::unique_lock<std::mutex> lock(mutex);
      terminate = true;
      cv.notify_one();
      return dap::DisconnectResponse{};
    });

    // Wait for the client to disconnect (or reach a 5 second timeout)
    // before releasing the session and disconnecting the socket to the
    // client.
    std::unique_lock<std::mutex> lock(mutex);
    cv.wait_for(lock, std::chrono::seconds(10), [&] { return terminate; });
    printf("Server closing connection\n");
  };

  // Error handler
  auto onError = [&](const char* msg) { printf("Server error: %s\n", msg); };

  // 创建并启动服务端
  const auto server = dap::net::Server::create();
  server->start(kPort, onClientConnected, onError);

  char c{};
  std::cin >> c;
}
